import 'package:flutter/cupertino.dart';
import 'package:kq_flutter_core_widget/utils/kq_screen_util.dart';
import 'package:kq_flutter_core_widget/config/kq_core_global.dart';
import '../../resources/kq_theme_colors.dart';

/// @author 高裕
/// 带气泡的组件
class KqTip extends StatefulWidget {
  const KqTip(this.text,
      {super.key,
      this.closeOnPanAgain = false,
      this.autoClose = true,
      this.aliveTime,
      this.tipDirection,
      this.windowPadding,
      this.arrowWidth,
      this.arrowHeight,
      this.backgroundColor,
      this.textColor,
      this.fontSize,
      this.tipsTextAlign,
      this.radius,
      this.tipsOffset,
      required this.child});

  /// 文本
  final String text;

  /// 二次按下是否关闭
  final bool? closeOnPanAgain;

  /// 是否自动关闭
  final bool? autoClose;

  /// 气泡存活时间，自动关闭下生效
  final Duration? aliveTime;

  /// 气泡上下位置
  final TipDirection? tipDirection;

  /// 文本和窗口间的padding
  final EdgeInsets? windowPadding;

  /// 箭头宽
  final double? arrowWidth;

  /// 箭头高
  final double? arrowHeight;

  /// 背景色
  final Color? backgroundColor;

  /// 文本颜色
  final Color? textColor;

  /// 字体大小
  final double? fontSize;

  /// 文本align
  final TextAlign? tipsTextAlign;

  /// 圆角
  final Radius? radius;

  /// tips相对于彩虹条的偏移量
  final double? tipsOffset;

  /// 子布局
  final Widget child;

  @override
  State<StatefulWidget> createState() {
    return KqTipState();
  }
}

class KqTipState extends State<KqTip> {
  /// 跟随标志
  final LayerLink layerLink = LayerLink();

  /// 悬浮框
  OverlayEntry? overlayEntry;

  /// 是否正在显示
  bool isShowing = false;

  /// 显示tip
  void show(BuildContext contextForTip) {
    if (isShowing == false) {
      overlayEntry = _createOverlayEntry(contextForTip);
      Overlay.of(context)?.insert(overlayEntry!);
      isShowing = true;
      if (widget.autoClose ?? true) {
        Future.delayed(widget.aliveTime ?? const Duration(milliseconds: 3000),
            () {
          close();
        });
      }
      return;
    }
    if (widget.closeOnPanAgain ?? false) {
      close();
    }
  }

  /// 主动关闭tip,用globeKey调用,要在最外层包个点击事件
  void close() {
    if (isShowing == true) {
      overlayEntry?.remove();
      isShowing = false;
    }
  }

  /// 生成悬浮窗
  OverlayEntry _createOverlayEntry(BuildContext contextForTip) => OverlayEntry(
        builder: (BuildContext context) => UnconstrainedBox(
          // 跟随者
          child: CompositedTransformFollower(
            link: layerLink,
            showWhenUnlinked: false,
            child: RepaintBoundary(
              child: CustomPaint(
                foregroundPainter: TipsPainter(
                  context: contextForTip,
                  text: widget.text,
                  tipDirection: widget.tipDirection ?? TipDirection.top,
                  windowPadding: widget.windowPadding ??
                      EdgeInsets.symmetric(vertical: 22.r, horizontal: 24.r),
                  arrowWidth: widget.arrowWidth ?? 24.r,
                  arrowHeight: widget.arrowHeight ?? 15.r,
                  backgroundColor:
                      widget.backgroundColor ?? KqThemeColors.textBlack65,
                  textColor: widget.textColor ?? KqThemeColors.bgWhite,
                  fontSize: widget.fontSize ?? 24.sp,
                  radius: widget.radius ?? Radius.circular(4.r),
                  tipsOffset: widget.tipsOffset ?? 4.r,
                  tipsTextAlign: widget.tipsTextAlign ?? TextAlign.center,
                ),
              ),
            ),
          ),
        ),
      );

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanDown: (details) {
        show(context);
      },
      onTap: () {
        /// 这里写一个空的onTap的目的是，与外层的onTap竞争，并胜出，来达到在该组件上点击时，不触发外层onTap的目的
      },
      // 被跟随者
      child: CompositedTransformTarget(
        link: layerLink,
        child: widget.child,
      ),
    );
  }
}

class TipsPainter extends CustomPainter {
  TipsPainter({
    Key? key,
    this.context,
    this.easyTipBox,
    required this.text,
    required this.tipDirection,
    required this.windowPadding,
    required this.arrowWidth,
    required this.arrowHeight,
    required this.backgroundColor,
    required this.textColor,
    required this.fontSize,
    required this.tipsTextAlign,
    required this.radius,
    required this.tipsOffset,
  });

  /// context和EasyTipBox必须传一个
  BuildContext? context;

  /// context和EasyTipBox必须传一个
  EasyTipBox? easyTipBox;

  /// 文本
  String text;

  /// 气泡上下位置
  final TipDirection tipDirection;

  /// 文本和窗口间的padding
  EdgeInsets windowPadding;

  /// 箭头宽
  double arrowWidth;

  /// 箭头高
  double arrowHeight;

  /// 背景色
  Color backgroundColor;

  /// 文本颜色
  Color textColor;

  /// 字体大小
  double fontSize;

  /// 文本align
  TextAlign tipsTextAlign;

  /// 圆角
  Radius radius;

  /// tips相对于child的偏移量
  double tipsOffset;

  @override
  void paint(Canvas canvas, Size size) {
    if (context == null && easyTipBox == null) {
      return;
    }
    RenderBox? renderBox = context?.findRenderObject() as RenderBox?;
    Size? boxSize = context?.size ?? easyTipBox?.boxSize;
    if (boxSize == null) {
      return;
    }
    // item的中心坐标(组件内)
    double centerPosition = boxSize.width / 2;
    // 组件内坐标与全局坐标的水平距离
    double globalLocalDx;
    if (context != null) {
      if (renderBox == null) {
        return;
      }
      Offset offset = renderBox.localToGlobal(Offset.zero);
      globalLocalDx = offset.dx;
    } else {
      globalLocalDx = easyTipBox!.globalLocalDx;
    }

    // 绘制
    drawArrow(canvas, centerPosition, boxSize);
    drawWindow(canvas, centerPosition, globalLocalDx, boxSize);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

  /// 绘制箭头
  void drawArrow(Canvas canvas, double centerPosition, Size boxSize) {
    Paint paint = Paint()
      ..style = PaintingStyle.fill
      ..color = backgroundColor;
    Path path = Path();
    if (tipDirection == TipDirection.top) {
      path.moveTo(centerPosition, -tipsOffset);
      path.lineTo(centerPosition - arrowWidth / 2, -arrowHeight - tipsOffset);
      path.lineTo(centerPosition + arrowWidth / 2, -arrowHeight - tipsOffset);
    } else {
      path.moveTo(centerPosition, tipsOffset + boxSize.height);
      path.lineTo(centerPosition - arrowWidth / 2,
          arrowHeight + tipsOffset + boxSize.height);
      path.lineTo(centerPosition + arrowWidth / 2,
          arrowHeight + tipsOffset + boxSize.height);
    }
    path.close();
    canvas.drawPath(path, paint);
  }

  /// 绘制窗口
  void drawWindow(Canvas canvas, double centerPosition, double globalLocalDx,
      Size boxSize) {
    Paint paint = Paint()
      ..style = PaintingStyle.fill
      ..color = backgroundColor;

    /// 生成绘制文本，但是先不绘制到画布上
    TextPainter textPainter = TextPainter(
      text: TextSpan(
        text: text,
        style: TextStyle(
          color: textColor,
          fontSize: fontSize,
        ),
      ),
      textAlign: tipsTextAlign,
      textDirection: TextDirection.ltr,
    );
    textPainter.layout(
        maxWidth: MediaQuery.of(KqCoreGlobal.globalContext).size.width -
            windowPadding.left -
            windowPadding.right);

    /// 计算tips中心点和宽度
    /// 判断绘制结果会不会在左右两侧超出屏幕
    /// 这里的移动距离特地加了1像素是为了美观
    double width = textPainter.width + windowPadding.left + windowPadding.right;
    double leftOverSize = centerPosition - width / 2 + globalLocalDx;
    double rightOverSize =
        MediaQuery.of(KqCoreGlobal.globalContext).size.width -
            (centerPosition + width / 2 + globalLocalDx);
    leftOverSize = leftOverSize < 0 ? -leftOverSize - 1.r : 0;
    rightOverSize = rightOverSize < 0 ? -rightOverSize - 1.r : 0;
    double centerHeight;
    if (tipDirection == TipDirection.top) {
      centerHeight = -tipsOffset -
          arrowHeight -
          windowPadding.bottom -
          textPainter.height / 2;
    } else {
      centerHeight = tipsOffset +
          arrowHeight +
          windowPadding.top +
          boxSize.height +
          textPainter.height / 2;
    }
    Offset center =
        Offset(centerPosition + leftOverSize - rightOverSize, centerHeight);
    Rect rect = Rect.fromCenter(
        center: center,
        width: textPainter.width + windowPadding.left + windowPadding.right,
        height: textPainter.height + windowPadding.top + windowPadding.bottom);
    canvas.drawRRect(RRect.fromRectAndRadius(rect, radius), paint);
    textPainter.paint(
        canvas,
        Offset(center.dx - textPainter.width / 2,
            center.dy - textPainter.height / 2));
  }
}

/// 简易气泡位置容器
class EasyTipBox {
  Size boxSize;

  // 组件内坐标与全局坐标的水平距离
  double globalLocalDx;

  EasyTipBox(this.boxSize, this.globalLocalDx);
}

/// 气泡位置
enum TipDirection {
  /// 上方
  top,

  /// 下方
  bottom;
}
